/**
 * Copyright (c) 2009 Koder Chen. All Rights Reserved.
 *
 * rsa.h
 * The file declares the functions used to finish the job needed to perform
 * the rsa encryption and decryption
 *
 *  Author: chenfuhan
 * Created: 2009-6-1
 * Version: 1.0
 */
#ifndef __RSA_RSA_H__
#define __RSA_RSA_H__

#include "type.h"

extern i32_t MAX_BITS;
extern i32_t MAX_BYTES;
extern u8_pt jacobi_a;
extern u8_pt jacobi_b;
extern u8_pt jacobi_r;
extern u8_pt jacobi_o;
extern u8_pt jacobi_t1;
extern u8_pt jacobi_t2;
extern u8_pt jacobi_x;
extern u8_pt jacobi_min;
extern u8_pt jacobi_nt;
extern u8_pt jacobi_nh;

/**
 * The structure for holding the datas for the rsa key map. It includes the needed
 * integers to go on with the process
 *
 * @package rsa
 */
typedef struct _rsa{
	i32_t max_bits;
	i32_t max_bytes;
	u8_t p[2048];
	u8_t q[2048];
	u8_t n[2048];
	u8_t e[2048];
	u8_t d[2048];
} rsa_key;

// function pointer
typedef void (*funcref) (u8_pt msg, u8_pt d, u8_pt n, u8_pt out);

/**
 * used to convert an integer into a bytes array
 *
 * @param a the integer to be converted
 * @param out the output data holder
 */
void rsa_conv_int2bytes(i32_t a, u8_pt out);

/**
 * used to convert a bytes array into an integer
 *
 * @param in the big integer, i.e. bytes array to be converted into normal integer
 * @return the converted integer
 */
i32_t rsa_conv_bytes2int(u8_pt in);

/**
 * Use to generate a random integer with the specified bits
 *
 * @param bits the number of bits to generate
 * @param out the output of the random integer
 */
void rsa_rand_bits(i32_t bits, u8_pt out);

/**
 * used to generate a big integer between min and max, that is min < a < max
 *
 * @param min the minimal of the generated big integer
 * @param max the maximal of the generated big integer
 * @param out the output of the generated integer
 */
void rsa_rand_int(u8_pt min, u8_pt max, u8_pt out);

/**
 * used to do a fermat test, to check whether the integer is probable a prime or
 * not
 *
 * @param a the big integer to be checked
 * @return 1 if it passes the fermat test, or 0 otherwise
 */
i32_t rsa_fermat_test(u8_pt a);

/**
 * used to calculate the jacobi number for the specified a and n
 *
 * @param m the base integer
 * @param n the the modulo
 */
i32_t rsa_jacobi(u8_pt m, u8_pt n);

/**
 * used to do the jacobi test, to check whether the integer is probable a prime or
 * not
 *
 * @param n the big integer to be checked
 * @param k the number of test loop
 * @return 1 if it passes the jacobi test, or 0 otherwise 
 */
i32_t rsa_jacobi_test(u8_pt n, i32_t k);

/**
 * Use to check whether the integer is a prime
 *
 * @param a the big integer to be checked whether it is an integer
 * @return 1 if it is a prime, or 0 otherwise
 */
i32_t rsa_check_prime(u8_pt a);

/**
 * a strong tester to test whether it is a prime
 *
 * @param a the big integer to be tested whether it is a prime integer
 * @return 1 if it is a prime, or 0 otherwise
 */
i32_t rsa_check_prime_strong(u8_pt a);

/**
 * Use to generate a random big prime
 *
 * @param bits the number of bits of the prime to generate
 * @param out the output of the random integer
 */
void rsa_rand_prime(i32_t bits, u8_pt out);

/**
 * it is used to test whether the two big integer is relatively prime
 *
 * @param a the first big integer
 * @param b the second big integer
 * @return 1 if they are relatively prime, or 0 otherwise
 */
i32_t rsa_relatively_prime(u8_pt a, u8_pt b);

/**
 * used to generate the prime p and q
 *
 * @param bits the number of bits
 * @param p the p value holder
 * @param q the q value holder
 */
void rsa_gen_p_q(i32_t bits, u8_pt p, u8_pt q);

/**
 * used to do the extended euclid gcd process, i.e. to find the value for the formula
 * d = gcd(a, b) = a*i + b * j;
 *
 * @param a the first big integer
 * @param b the second big integer
 * @param d the gcd(a, b)
 * @param k the coefficient for a
 * @param l the coefficient for b
 */
void rsa_extended_euclid_gcd(u8_pt a, u8_pt b, u8_pt d, u8_pt k, u8_pt l, i32_pt markX, i32_pt markY);

/**
 * used to calculate the keys using the specified prime number a and b
 *
 * @param a the first prime number
 * @param b the second prime number
 * @param the number of bits to fetch
 * @param eOut the value for 'e' in rsa algorithm
 * @param dOut the value for 'd' in rsa algorithm
 */
i32_t rsa_calculate_keys(i8_t bits, u8_pt a, u8_pt b, u8_pt eOut, u8_pt dOut);

/**
 * used to generates the public and private keys for the rsa system
 *
 * @param bits the number of bits of the keys
 * @param keys the key holder
 */
void rsa_gen_keys(i32_t bits, rsa_key *keys);

/**
 * used to encrypt a big integer into an encrypted msg.
 *
 * @param msg the msg to be encrpyted
 * @param e the e key, it is a big integer
 * @param n the n number, it is a big integer
 * @param out the encrypted string holder
 */
void rsa_encrypt_bigint(u8_pt msg, u8_pt e, u8_pt n, u8_pt out);

/**
 * used to decrypt a big integer
 *
 * @param msg the msg to be decrypted
 * @param d the d key, it is a big integer
 * @param n the n number, it is a big integer
 * @param out the decrypted string holder
 */
void rsa_decrypt_bigint(u8_pt msg, u8_pt d, u8_pt n, u8_pt out);

/**
 * used to signature a big integer
 *
 * @param msg the msg to be signatured
 * @param d the d key, it is a big integer
 * @param n the n number, it is a big integer
 * @param out the signatured string holder
 */
void rsa_sign_bigint(u8_pt msg, u8_pt d, u8_pt n, u8_pt out);

/**
 * used to verify a big integer
 *
 * @param msg the msg to be verified
 * @param d the d key, it is a big integer
 * @param n the n number, it is a big integer
 * @param out the verified string holder
 */
void rsa_verify_bigint(u8_pt msg, u8_pt e, u8_pt n, u8_pt out);

/**
 * this method is to chop a string into the match form, i.e. with the same
 * bits with the big integer 'n', and the encrypt or decrypt one by one
 *
 * @param msg the msg to be choped
 * @param d the d key, it is a big integer
 * @param n the n number, it is a big integer
 * @param out the choped and enrypted/decrypted string holder
 */
i32_t rsa_chopstring(u8_pt msg, u8_pt key, u8_pt n, u8_pt out, i32_t len, funcref func);

/**
 * this method is to glue a string from the chop form, i.e. with the same
 * bits with the big integer 'n', and the encrypt or decrypt one by one
 *
 * @param msg the msg to be glued
 * @param d the d key, it is a big integer
 * @param n the n number, it is a big integer
 * @param out the glued and enrypted/decrypted string holder
 */
i32_t rsa_gluechops(u8_pt chops, u8_pt e, u8_pt n, u8_pt out, i32_t len, funcref func);

#endif // __RSA_RSA_H__
